﻿/*
 * SeparatedBitmapBlock
 * 
 * initial implementation : 20.10.2008
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
using System.IO;
using System.Collections.Generic;
//using System.Drawing;
//using System.Drawing.Imaging;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;


namespace Petra.Gis.ImagingServices.Tiff
{

  /// <summary>
  /// represents block that is organized in special way bitmap
  /// where each color band goes like RRRR....GGGG....BBBB....
  /// each block contains only one color
  /// current implementation does not support block with different bitsPerSample for color band
  /// </summary>
  public class SeparatedBitmapBlock : BitmapBlock
  {

    private List<byte[]> _samples;
    private int _numOfPlanes;
    //private int _blockId; //pointer to first sample block on disk, this BitmapBlock will read more than one block
    private TiffReader _sourceData;
    private int _bps; //bitsPerSample value


    #region constructors

    /// <summary>
    /// basic constructor, creates BitmapBlock from dimensions only
    /// </summary>
    /// <param name="bounds">block position and size</param>
    /// <param name="PixelFormat">format of pixel for this block</param>
    public SeparatedBitmapBlock(BlockBitmapSource parentBitmap, Int32Rect bounds, Metadata metadata, int blockId)
      : base(parentBitmap, bounds, blockId)
    {
      //if (!(pixelFormat == PixelFormats.Gray8 || pixelFormat == PixelFormats.Gray16))
      //  throw new ArgumentException("unsupported pixel format for " + this.GetType().ToString());

      if (metadata.PlanarConfiguration != PlanarConfigurationType.Separate)
        throw new ArgumentException("invalid TiffMetadata for " + 
                                     this.GetType().ToString() +
                                     " must be " + PlanarConfigurationType.Separate.ToString());

      _numOfPlanes = metadata.SamplesPerPixel;
    }




    ///// <summary>
    ///// creates BitmapBlock from existing bitmap
    ///// </summary>
    ///// <param name="sourceBmp"></param>
    ///// <param name="areaOfInterest"></param>
    //public SeparatedBitmapBlock(BlockBitmapSource parentBitmap, 
    //                            BitmapSource sourceBmp, 
    //                            Int32Rect areaOfInterest, 
    //                            BitmapOperationType oType 
    //                            )
    //  : base(parentBitmap, areaOfInterest, oType)
    //{
    //  if (_parent.TiffMetadata.PlanarConfiguration != PlanarConfigurationType.Separate)
    //    throw new ArgumentException("invalid TiffMetadata for " + 
    //                                 this.GetType().ToString() +
    //                                 " must be " + PlanarConfigurationType.Separate.ToString());

    //  _numOfPlanes = _parent.TiffMetadata.SamplesPerPixel;

    //}



    /// <summary>
    /// create SeparatedBitmapBlock from tiff file
    /// metadata is necessary to determine bitsPerSample to prepare valid bitmaps..
    /// </summary>
    /// <param name="bounds">position of this SeparatedBitmapBlock in parent image</param>
    /// <param name="sourceData">TiffReader</param>
    /// <param name="metadata">TiffMetadata</param>
    /// <param name="firstSampleBlockOffset">index of this SeparatedBitmapBlock in parent image</param>
    internal SeparatedBitmapBlock(BlockBitmapSource parentBitmap, 
                                Int32Rect bounds, 
                                int blockId)
      : base(parentBitmap, bounds, blockId)
    {
      if (_parent.TiffMetadata.PlanarConfiguration != PlanarConfigurationType.Separate)
        throw new ArgumentException("invalid input image or metadata, must correspond");

      if (_parent.TiffMetadata.SamplesPerPixel < 1)
        throw new ArgumentException("invalid input image or metadata, must correspond");

      //validate bitsPerSample
      int bps1 = _parent.TiffMetadata.BitsPerSamples[0];
      for (int i = 0; i < _parent.TiffMetadata.BitsPerSamples.Length; i++)
      {
        if (_parent.TiffMetadata.BitsPerSamples[i] != bps1)
          throw new ArgumentException(" sorry, images with different bitsPerSample unsupported");
      }

      _bps = bps1;


      _numOfPlanes = _parent.TiffMetadata.SamplesPerPixel;

      if (_parent.DataReader == null)
        throw new ArgumentException("cant create separate block withouth file");

      _sourceData = _parent.DataReader;

    }



    #endregion constructors


    #region public members


    protected override void CopyPixelsCore(Int32Rect sourceRect, int stride, int bufferSize, IntPtr buffer)
    {

      this.Source.CopyPixels(sourceRect, buffer, bufferSize, stride);
    }


    public BitmapSource Source
    {
      get
      {
        return loadData();
      }
      set
      {
        throw new NotImplementedException();
      }
    }



    public List<byte[]> Samples
    {
      get { return _samples; }
    }


    /// <summary>
    /// this will load data from image into block
    /// decompress if needed
    /// convert color schema if needed
    /// </summary>
    private BitmapSource loadData()
    {
      BitmapSource data;

      //if bitmap created as empty initialize new
      //if (_samples == null)
      //  initialize(_numOfPlanes, _bps);
      //else
      //{
        //prepare bitmaps
        _samples = new List<byte[]>();

        for (int i = 0 ; i < _numOfPlanes ; i++)
        {

          //load (and decompress) data from image int new bitmap
          _sourceData.BaseStream.Seek(_parent.TiffMetadata.BlockOffsets[_blockId + i], SeekOrigin.Begin);
          _samples.Add(_parent.Compression.DecompressBlock(this, _sourceData.ReadBytes((int)_parent.TiffMetadata.BlockLengths[_blockId + i]), _parent.TiffMetadata.BitsPerSamples[0]));
          //((TiffBitmapPage)_parent).Decoder.TiffReader.BaseStream.Seek(_metadata.BlockOffsets[_blockId + i], SeekOrigin.Begin);
          //rawDecompressedData = ((TiffBitmapPage)_parent).Compression.DecompressBlock(this, ((TiffBitmapPage)_parent).Decoder.TiffReader.ReadBytes(_metadata.BlockLengths[_blockId + i]), _metadata.BitsPerSamples[0]);
         
        }
      
      //}
        //from _blockId + index of sample
        byte[] colorConvertedData = ColorSpaceConverter.Convert(this, _parent.TiffMetadata.PixelFormat, PixelFormats.Rgb24);
        data = BitmapSource.Create(_bounds.Width, _bounds.Height, 600, 600, PixelFormats.Rgb24, null, colorConvertedData, BitmapBlock.GetStrideLenght(_bounds.Width, PixelFormats.Rgb24.BitsPerPixel));

        return data;

    }


    ///// <summary>
    ///// returns (compressed) size of current stripe or tile in bytes
    ///// </summary>
    //public int CompressedSize
    //{
    //  get 
    //  {
    //    if (_image.Metadata.IsTiled)
    //      return System.Convert.ToInt32(_image.Metadata.Ifd.GetTag(TagType.TILEBYTECOUNTS).TagData[_blockIndex]);
    //    else
    //      return System.Convert.ToInt32(_image.Metadata.Ifd.GetTag(TagType.STRIPBYTECOUNTS).TagData[_blockIndex]);
    //  }
    //}

    #endregion public members


    #region private members

    ///// <summary>
    ///// initializes this BitmapBlock with new empty bitmap
    ///// </summary>
    //private void initialize(int numOfPlanes, int bps)
    //{

    //  for (int i = 0; i < numOfPlanes; i++)
    //  {
    //    switch (bps)
    //    {
    //      case 8:
    //        _bands.Add(new RenderTargetBitmap(_bounds.Width, _bounds.Height, 600, 600, PixelFormats.Gray8));
    //        break;
    //      case 16:
    //        _bands.Add(new RenderTargetBitmap(_bounds.Width, _bounds.Height, 600, 600, PixelFormats.Gray16));
    //        break;
    //      default:
    //        throw new ArgumentException("sorry, unsupported pixel format");
    //    }
    //  }


    //}

    #endregion private members

  }
}
